package net.ba.map
{
	import com.google.maps.LatLng;
	import com.google.maps.LatLngBounds;
	import com.google.maps.MapMoveEvent;
	import com.google.maps.interfaces.IMap;
	import com.google.maps.interfaces.IOverlay;
	import com.google.maps.interfaces.IPane;
	import com.google.maps.overlays.Polyline;
	import com.google.maps.overlays.PolylineOptions;
	import com.google.maps.styles.StrokeStyle;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	import mx.core.Application;

	public class GridOverlay implements IOverlay
	{
		
		private var map:IMap;
		private var linesArray:Array;
		private var lineColor:Number;
		private var linesHided:Boolean;
		private var lineOptions:PolylineOptions = new PolylineOptions();
		private var ss:StrokeStyle = new StrokeStyle();
		private var currentZoomLevel:Number;
		private var currentBbox:LatLngBounds;
		private var isInitialized:Boolean = false;
		
		
		public function GridOverlay()
		{
		}

		public function initialize(_pane:IPane):void
		{
			init();
		}
		
		public function init():void {
			this.map = Application.application.mapContainer.map;
			this.linesArray = new Array();
			linesHided=true;
			
			ss.thickness = 1;
			ss.alpha = 0.7;
			lineOptions.strokeStyle = ss;
			
			currentZoomLevel = map.getZoom();
			currentBbox = map.getLatLngBounds();
			
			//Add listeners
			map.addEventListener(MapMoveEvent.MOVE_END,function (ev:Event):void{forceRedraw();});
			
			isInitialized = true;
			
		}
		
		public function remove():void
		{
			for each (var l:Polyline in this.linesArray) {
				this.map.removeOverlay(l);
			}
			linesArray = new Array();
			
		}
		
		public function show():void
		{
			linesHided = false;
			forceRedraw();
			lineOptions.strokeStyle.alpha = 0.7;
			for each(var line:Polyline in linesArray) {
				line.setOptions(lineOptions);
			}
		}
		
		public function isHidden():Boolean
		{
			return linesHided;
		}
		
		public function hide():void
		{
			linesHided = true;
			remove();
		}
		
		public function forceRedraw():void {
			if (!linesHided) {
				redraw(true);
			}
		}
		
		public function redraw(force:Boolean):void
		{
			if (!isInitialized) {
				init();
			} else {
				//clear old
	  			this.remove();
			}
  			
  			//best color for writing on the map
  			lineColor = this.map.getCurrentMapType().getTextColor();
			ss.color = lineColor;
			lineOptions.strokeStyle = ss;
  			
  			//determine graticule interval
  			var bnds:LatLngBounds = this.map.getLatLngBounds();
			var l:Number = bnds.getSouthWest().lng();
			var b:Number = bnds.getSouthWest().lat();
			var t:Number = bnds.getNorthEast().lat();
			var r:Number = bnds.getNorthEast().lng();			
			trace(l+"-"+b+"-"+t+"-"+r+"-");			
			
			//sanity
			if (b < -90.0)
				b = -90.0;
			if(t > 90.0)
				t = 90.0;
			if(l < -180.0)
			    l = -180.0;  
			if(r > 180.0)
			    r = 180.0;    
			if(l == r){
				l = -180.0;
				r = 180.0;
			}
			if(t == b){
				b = -90.0;
				t = 90.0;
			}
			
			//grid interval in minutes    
			var dLat:Number =1;
			var dLng:Number =1; 		    
			
			 //round iteration limits to the computed grid interval
			 l = Math.floor(l/dLng);
			 b = Math.floor(b/dLat);
			 t = Math.ceil(t/dLat);
			 r = Math.ceil(r/dLng);			 
			 
			   //Sanity
			 if (b <= -90.0)
				b = -90;
			 if(t >= 90.0)
				t = 90;
			 if(l < -180.0)
			    l = -180.0;  
			 if(r > 180.0)
			    r = 180.0;
			
			var lo:Number = l;//copy to save original
						
			//preserve r
			var ro:Number = r;
			if(ro<lo)
			      ro += 360.0;

			var line:Polyline;
			//vertical lines
			while(lo<=ro){		
				line = new Polyline([new LatLng(t,lo),new LatLng(b,lo)],lineOptions);
				linesArray.push(line);
				this.map.addOverlay(line);			
				
				lo += dLng;	
				if (lo > 180.0){
					ro -= 360.0;
					lo -= 360.0;
				}
			}	
			
			if (r>180)
				r=180;
			if (r<-180)
				r=-180;				
			if (l>180)
				l=180;
			if (l<-180)
				l=-180;
				
			//sort l and r to be left and right
			var x:Number;
			if (l>0 && l<r){
				x=r;
				r=l;
				l=x;
			}
			if (l<0 && l>r) {
				x=r;
				r=l;
				l=x;
			}
						
			//Horizontal Lines
			while(b<=t){	
				//check if the lines are gonna cross the greenwich meridian
				if ((l>0 && r>0) || ((l<0 && r<0) )) {
					line = new Polyline([new LatLng(b,l),new LatLng(b,r)],lineOptions);
					linesArray.push(line);
					this.map.addOverlay(line);
				}else {
					if ((l<0 && r>0)) {
						//Till the 0
						line = new Polyline([new LatLng(b,l),new LatLng(b,-0.00001)],lineOptions);
						linesArray.push(line);
						this.map.addOverlay(line);	
						
						//from the 0					
						line = new Polyline([new LatLng(b,0.00001),new LatLng(b,r)],lineOptions);
						linesArray.push(line);
						this.map.addOverlay(line);		
						
					} else {
						//Till the 180
						line = new Polyline([new LatLng(b,l),new LatLng(b,179.9999)],lineOptions);
						linesArray.push(line);
						this.map.addOverlay(line);	
						
						//from the 0					
						line = new Polyline([new LatLng(b,-179.9999),new LatLng(b,r)],lineOptions);
						linesArray.push(line);
						this.map.addOverlay(line);							
						
					}
				}
								
				b += dLat; 
			}	
				      
		}
		
		
		public function get interfaceChain():Array
		{
			return null;
		}
		
		public function get wrapper():Object
		{
			return null;
		}
		
		public function set wrapper(arg0:Object):void
		{
		}
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return false;
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return false;
		}
		
		public function willTrigger(type:String):Boolean
		{
			return false;
		}				
		public function getDefaultPane(arg0:IMap):IPane
		{
			return null;
		}
		public function getDisplayObject():DisplayObject
		{
			return null;
		}
		
		public function getPane():IPane
		{
			return null;
		}	
		
		public function positionOverlay(arg0:Boolean):void
		{
		}	
		
	}
}